package site.anxuan.seckill.controller;

import com.google.common.util.concurrent.RateLimiter;
import com.yufeixuan.captcha.Captcha;
import com.yufeixuan.captcha.GifCaptcha;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import site.anxuan.seckill.common.BusinessException;
import site.anxuan.seckill.common.ErrorCode;
import site.anxuan.seckill.common.Results;
import site.anxuan.seckill.entity.Result;
import site.anxuan.seckill.entity.User;
import site.anxuan.seckill.service.OrderService;
import site.anxuan.seckill.service.PromotionService;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;

@RestController
@RequestMapping("/order")
public class OrderController {

    private final Logger logger = LoggerFactory.getLogger(OrderController.class);

    private final RedisTemplate<String, Object> redisTemplate;

    private final PromotionService promotionService;

    private final OrderService orderService;

    @SuppressWarnings("all")
    private final RateLimiter rateLimiter = RateLimiter.create(5000);

    @Qualifier("orderTaskPool")
    private final ThreadPoolExecutor orderTaskPool;

    @Autowired
    public OrderController(RedisTemplate<String, Object> redisTemplate,PromotionService promotionService,
                           OrderService orderService, ThreadPoolExecutor orderTaskPool) {
        this.redisTemplate = redisTemplate;
        this.promotionService = promotionService;
        this.orderService = orderService;
        this.orderTaskPool = orderTaskPool;
    }

    @GetMapping(value = "/captcha", produces = MediaType.IMAGE_GIF_VALUE)
    public void getCaptcha(String token, HttpServletResponse response) {
        User user = (User) redisTemplate.opsForValue().get("loginToken:" + token);
        if (token != null && user != null) {
            Captcha captcha = new GifCaptcha(130, 48, 4);
            try {
                OutputStream outputStream = response.getOutputStream();
                captcha.out(outputStream);
                redisTemplate.opsForValue().set("order:captcha:" + user.getId(), captcha.text());
            } catch (IOException e) {
                logger.error("发送验证码失败：" + e.getMessage());
            }
        }
    }

    @PostMapping("/token")
    public Result<String> getPromotionToken(Integer itemId, Integer promotionId, String captcha, String token) {
        if (itemId < 0 || promotionId == null) {
            throw new BusinessException(ErrorCode.PARAMETER_ERROR, "参数不合法");
        }
        if (!StringUtils.hasText(captcha)) {
            throw new BusinessException(ErrorCode.PARAMETER_ERROR, "请输入正确的验证码！");
        }
        User user = (User) redisTemplate.opsForValue().get("loginToken:" + token);
        String text = (String) redisTemplate.opsForValue().get("order:captcha:" + user.getId());
        if (!StringUtils.hasText(text) || !text.equalsIgnoreCase(captcha)) {
            throw new BusinessException(ErrorCode.PARAMETER_ERROR, "请输入正确的验证码！");
        }
        String promotionToken = promotionService.generateToken(user.getId(), itemId, promotionId);
        if (!StringUtils.hasText(promotionToken)) {
            throw new BusinessException(ErrorCode.CREATE_ORDER_FAILURE, "下单失败！");
        }
        return Results.success(promotionToken);
    }

    @PostMapping("/create")
    public Result<Void> create(int itemId, int amount, Integer promotionId,
                               String promotionToken, String token) {
        if (itemId < 0 || amount <= 0) {
            throw new BusinessException(ErrorCode.PARAMETER_ERROR, "参数不合法");
        }

        User user = (User) redisTemplate.opsForValue().get("loginToken:" + token);
        // 登录信息失效
        if (user == null) {
            throw new BusinessException(ErrorCode.CREATE_ORDER_FAILURE, "下单失败！");
        }

        // 校验活动Token
        if (promotionId != null && promotionId <= 0) {
            String key = "item:promotion:token:" + itemId + ":" + promotionId + ":" + user.getId();
            String storedPromotionToken = (String) redisTemplate.opsForValue().get(key);
            if (storedPromotionToken == null || !storedPromotionToken.equals(promotionToken)) {
                throw new BusinessException(ErrorCode.CREATE_ORDER_FAILURE, "下单失败！");
            }
        }

        // 校验库存
        Boolean saleOut = redisTemplate.hasKey("item:stock:out:" + itemId);
        if (saleOut != null && saleOut) {
            throw new BusinessException(ErrorCode.STOCK_NOT_ENOUGH, "库存不足！");
        }

        // 创建订单
        Future<Object> future = orderTaskPool.submit(() -> {
            orderService.createLocalTransaction(user.getId(), itemId, amount, promotionId);
            return null;
        });

        try {
            future.get();
        } catch (Exception e) {
            throw new BusinessException(ErrorCode.CREATE_ORDER_FAILURE, "下单失败！");
        }

        return Results.success();
    }

}
